package org.dromara.assets.biz;

import java.math.BigDecimal;
import java.util.*;

import com.binance.api.client.domain.account.Order;
import org.dromara.assets.domain.bo.AssetsTradeRecordBo;
import org.dromara.assets.domain.vo.AssetsTradeRecordVo;
import org.dromara.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mail.utils.MailUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.dromara.assets.domain.AssetsTradeRecord;
import org.dromara.assets.service.IAssetsTradeRecordService;

import static org.dromara.assets.biz.BinanceBiz.dataCache;

/**
 * 交易记录Service业务层处理
 *
 * @author Edward
 * @date 2022-08-25
 */
@Service
@Slf4j
public class AssetsTradeRecordServiceBiz {

    @Autowired
    private IAssetsTradeRecordService tradeRecordService;

    public static List<String> nonFinalState = Arrays.asList("PENDING", "NEW", "TRADING", "PARTIALLY_FILLED");
    public static List<String> finalState = Arrays.asList("FILLED", "CANCELED");

    public boolean syncItem(String symbol, Order order, Long accountId) {
        Long orderId = order.getOrderId();
        //TODO待补充platform
        AssetsTradeRecordVo assetsTradeRecordVo = tradeRecordService.queryByOrderId(orderId);
        boolean isNew = false;
        boolean isUpdate = false;
        if (assetsTradeRecordVo == null) {
            isNew = true;
            AssetsTradeRecordBo assetsTradeRecordBo = new AssetsTradeRecordBo();
            assetsTradeRecordBo.setPlatform(Long.parseLong("1"));
            assetsTradeRecordBo.setOrderid(order.getOrderId() + "");
            assetsTradeRecordBo.setTokenPair(symbol);
            assetsTradeRecordBo.setPrice(new BigDecimal(order.getPrice()));
            assetsTradeRecordBo.setAmount(new BigDecimal(order.getOrigQty()));
            assetsTradeRecordBo.setFilledAmount(new BigDecimal(order.getExecutedQty()));
            assetsTradeRecordBo.setFilledCashAmount(new BigDecimal(order.getCummulativeQuoteQty()));
            assetsTradeRecordBo.setState(order.getStatus().toString());
            assetsTradeRecordBo.setOrderType(order.getSide().toString());
            assetsTradeRecordBo.setCreateAt(new Date(order.getTime()));
            assetsTradeRecordBo.setFinishAt(new Date(order.getUpdateTime()));
            assetsTradeRecordBo.setAccountId(accountId);
            tradeRecordService.insertByBo(assetsTradeRecordBo);
        } else if (nonFinalState.contains(assetsTradeRecordVo.getState())) {
            //# 如果为非最终状态，则更新
            isUpdate = true;
            AssetsTradeRecordBo assetsTradeRecord4Update = new AssetsTradeRecordBo();
            assetsTradeRecord4Update.setPlatform(Long.parseLong("1"));
            assetsTradeRecord4Update.setAmount(new BigDecimal(order.getOrigQty()));
            assetsTradeRecord4Update.setFilledAmount(new BigDecimal(order.getExecutedQty()));
            // assetsTradeRecord.setFilledCashAmount(tradeRecord.);
            assetsTradeRecord4Update.setState(order.getStatus().toString());
            assetsTradeRecord4Update.setId(assetsTradeRecordVo.getId());
            tradeRecordService.updateByBo(assetsTradeRecord4Update);
        } else if (order.getStatus().toString().equals("CANCELED") && new BigDecimal(order.getExecutedQty()).compareTo(BigDecimal.ZERO) != 0
            && !assetsTradeRecordVo.getState().equals("FILLED")) {
            //部分成交后取消订单，则将状态置为已成交
            isUpdate = true;
            AssetsTradeRecordBo assetsTradeRecord4Update = new AssetsTradeRecordBo();
            assetsTradeRecord4Update.setFilledAmount(new BigDecimal(order.getExecutedQty()));
            assetsTradeRecord4Update.setState("FILLED");
            assetsTradeRecord4Update.setId(assetsTradeRecordVo.getId());
            tradeRecordService.updateByBo(assetsTradeRecord4Update);
        }
        if ((isNew || isUpdate) && order.getStatus().toString().equals("FILLED")) {
            log.info("应该发送邮件");
            //检查回调函数
            filledCallBack(order.getOrderId());
            //发送邮件
            String sendEmailResult = sendEmail("1", order);
            log.info("sendEmailResult result:{}", sendEmailResult);
        }
        if (finalState.contains(order.getStatus().toString())) {
            dataCache.addData(symbol, order.getOrderId().toString());
        }
        return isNew;
    }

    /**
     * 成交回调函数
     */
    public void filledCallBack(Long orderId) {
        //检查是否有设置回调
        //如果有回调则按照设置的回调下单
    }


    public static String sendEmail(String platform, Order tradeRecord) {
        log.info("sendEmail method called");
        // 构建 HTML 内容
        StringBuilder content = new StringBuilder();
        content.append("<html>")
            .append("platform: ").append("Binance").append("<br>").append("symbol: ").append(tradeRecord.getSymbol()).append("<br>").append("side: ").append(tradeRecord.getSide().toString()).append("<br>").append("amount: ").append(tradeRecord.getExecutedQty()).append("<br>");
        try {
            content.append("price: ").append(tradeRecord.getPrice()).append("<br>");
        } catch (Exception e) {
            log.error("Exception occurred", e);
            content.append("Exception occurred, price: ").append(tradeRecord.getPrice()).append("<br>");
        }
        content.append("</html>");
        log.info("Email content:{}", content);
        String subject = "您有新的邮件（消息）";
        return MailUtils.sendHtml("8607071@qq.com", subject, content.toString());
        //Task.sendHtmlEmail(parms, receivers, subject, content.toString());
    }

    public R<Void> close(Long[] ids) {
        // 检查是否选择了两笔记录
        if (ids == null || ids.length != 2) {
            return R.fail("必须或者只能选择两笔记录");
        }

        // 查询两笔交易记录
        Long id1 = ids[0];
        Long id2 = ids[1];

        AssetsTradeRecord tradeRecord1 = MapstructUtils.convert(tradeRecordService.queryById(id1),
            AssetsTradeRecord.class);
        AssetsTradeRecord tradeRecord2 = MapstructUtils.convert(tradeRecordService.queryById(id2),
            AssetsTradeRecord.class);

        if (tradeRecord1 == null || tradeRecord2 == null) {
            return R.fail("交易记录不存在");
        }

        // 校验交易币种是否相同
        if (!tradeRecord1.getTokenPair().equals(tradeRecord2.getTokenPair())) {
            return R.fail("不是一个交易币种不能平仓");
        }

        // 校验平台是否相同
        if (!tradeRecord1.getPlatform().equals(tradeRecord2.getPlatform())) {
            return R.fail("不是一个平台不能平仓");
        }

        // 校验交易状态是否为已成交
        if (!"FILLED".equals(tradeRecord1.getState()) || !"FILLED".equals(tradeRecord2.getState())) {
            return R.fail("未成交状态不能平仓");
        }

        // 判断交易时间，确定平仓单与被平仓单
        AssetsTradeRecord fromTradeRecord = null;
        AssetsTradeRecord beforeUpdateTradeRecord = null;

        if (tradeRecord1.getCreateAt().after(tradeRecord2.getCreateAt())) {
            fromTradeRecord = tradeRecord2;
            beforeUpdateTradeRecord = tradeRecord1;
        } else {
            fromTradeRecord = tradeRecord1;
            beforeUpdateTradeRecord = tradeRecord2;
        }

        // 校验是否已经关联过
        if (beforeUpdateTradeRecord.getFromOrderid() != null
            && beforeUpdateTradeRecord.getFromOrderid().contains(fromTradeRecord.getOrderid())) {
            return R.fail("两笔记录已经关联过了");
        }

        // 计算未平仓数量
        BigDecimal unBackwardAmountFrom = fromTradeRecord.getFilledAmount().subtract(fromTradeRecord.getBackwardAmount());
        BigDecimal unBackwardAmountThis =
            beforeUpdateTradeRecord.getFilledAmount().subtract(beforeUpdateTradeRecord.getBackwardAmount());

        if (unBackwardAmountFrom.compareTo(BigDecimal.ZERO) <= 0 || unBackwardAmountThis.compareTo(BigDecimal.ZERO) <= 0) {
            return R.fail("平仓或者被平仓数量不能为0");
        }

        // 计算实际平仓数量
        BigDecimal backwardAmount = unBackwardAmountFrom.compareTo(unBackwardAmountThis) < 0 ? unBackwardAmountFrom :
            unBackwardAmountThis;

        // 计算赚取金额
        BigDecimal winAmount;

        boolean thisIsSell = isSell(beforeUpdateTradeRecord.getOrderType());
        boolean tmpIsSell = isSell(fromTradeRecord.getOrderType());

        if (thisIsSell) {
            if (tmpIsSell) {
                return R.fail("两个单不能都为卖单");
            } else {
                winAmount =
                    backwardAmount.multiply(beforeUpdateTradeRecord.getPrice()).subtract(backwardAmount.multiply(fromTradeRecord.getPrice()));
            }
        } else {
            if (!tmpIsSell) {
                return R.fail("两个单不能都为买单");
            } else {
                winAmount =
                    backwardAmount.multiply(fromTradeRecord.getPrice()).subtract(backwardAmount.multiply(beforeUpdateTradeRecord.getPrice()));
            }
        }
        // 更新数据库
        updateTradeRecord(fromTradeRecord, backwardAmount);
        updateTradeRecord(beforeUpdateTradeRecord, backwardAmount, winAmount, fromTradeRecord.getOrderid());
        return R.ok("平仓成功");
    }

    private boolean isSell(String orderType) {
        // 判断订单类型是否为卖单
        return "SELL".equalsIgnoreCase(orderType);
    }

    private void updateTradeRecord(AssetsTradeRecord record, BigDecimal backwardAmount) {
        // 更新平仓数量
        record.setBackwardAmount(record.getBackwardAmount().add(backwardAmount));
        saveTradeRecord(record);
    }

    private void updateTradeRecord(AssetsTradeRecord record, BigDecimal backwardAmount, BigDecimal winAmount,
                                   String fromOrderId) {
        // 更新平仓数量、赚取金额和关联订单ID
        record.setBackwardAmount(record.getBackwardAmount().add(backwardAmount));
        record.setWinAmount(record.getWinAmount().add(winAmount));
        record.setFromOrderid(fromOrderId);
        saveTradeRecord(record);
    }

    private void saveTradeRecord(AssetsTradeRecord record) {
        tradeRecordService.updateById(record);
    }
}


